package org.jeecg.modules.userReports.job;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.reportCronJobData.entity.ReportCronJobData;
import org.jeecg.modules.reportCronJobData.service.IReportCronJobDataService;
import org.jeecg.modules.userReports.entity.UserReports;
import org.jeecg.modules.userReports.entity.UserReportsField;
import org.jeecg.modules.userReports.service.IUserReportsFieldService;
import org.jeecg.modules.userReports.service.IUserReportsService;
import org.jeecg.modules.userReports.vo.BuildReport;
import org.jeecg.modules.userReports.vo.BuildReportParam;
import org.jeecg.modules.util.HttpClientUtil;
import org.jeecgframework.poi.excel.ExcelExportUtil;
import org.jeecgframework.poi.excel.entity.TemplateExportParams;
import org.jetbrains.annotations.NotNull;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class userReportsJob implements Job {
    @Autowired
    private IUserReportsService userReportsService;
    @Autowired
    private IUserReportsFieldService userReportsFieldService;
    @Autowired
    private IReportCronJobDataService reportCronJobDataService;
    @Value("${zfservice.url}")
    private String zfserviceUrl;

    @Value("${report-tmp.path}")
    private String reportTmpPath;

    @Value(value = "${report-tmp.export-path}")
    private String exportPath;


    private String parameter;

    public void setParameter(String parameter) {
        this.parameter = parameter;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info("生成报告：" + jobExecutionContext.getJobDetail().getKey());
        log.info("生成报告定时任务 DataReportJob !  时间:{}", DateUtils.getTimestamp());
        JSONObject jsonObject = JSONObject.parseObject(parameter);

        String reportId = jsonObject.get("reportId").toString();
        if(jsonObject.containsKey("dateUntreated")&&StringUtils.isNotEmpty(jsonObject.get("dateUntreated").toString())){
            List<String> dateUntreated = (List<String>) JSONObject.parse(jsonObject.get("dateUntreated").toString());
            for (int i = 0; i < dateUntreated.size(); i++) {
                buildReport(reportId, LocalDate.parse(dateUntreated.get(i)));
            }
            return;
        }

        LocalDate calcDate = LocalDate.now().minusDays(1);
        buildReport(reportId, calcDate);
    }

    private void buildReport(String reportId, LocalDate calcDate) {
        log.info("生成报告定时任务 calcDate:{}", calcDate);
        UserReports userReports = userReportsService.getById(reportId);
        if (userReports == null) {
            throw new Error("未找到对应数据");
        }

        List<UserReportsField> userReportsFieldList = userReportsFieldService.selectByMainId(reportId);
        if (StringUtils.isNotEmpty(userReports.getTableName())) {
            log.info("报告设置指定的有对应的表：{}", userReports.getTableName());
            List<Map<String, Object>> result = userReportsService.getTableByCalcDate(userReports.getTableName(), calcDate.toString());
            if (result != null && result.size() > 0) {
                // String fileUrl = this.exportXls(userReports.getReportName(),maps,result,  userReportsFieldList, calcDate.toString());
                this.exportXls(reportId, userReports.getReportName(),
                        Date.from(calcDate.atStartOfDay(ZoneId.systemDefault()).toInstant()),
                        null, result, userReportsFieldList);
                return;
            }
        } else {
            for (int j = 1; j < userReportsFieldList.size() + 1; j++) {
                userReportsFieldList.get(j - 1).setTableColumn("vl_" + j);
            }
            userReportsFieldService.updateBatchById(userReportsFieldList);
            List<String> colums = userReportsFieldList.stream().map(o -> o.getTableColumn()).collect(Collectors.toList());
            //动态创建表
            String tableName = "tb_report_" + DateUtils.date2Str(new Date(), DateUtils.yyyymmddhhmmss.get());
            log.info("报告没有对应的表，新建了表：{}", tableName);
            this.userReportsService.createTable(tableName, colums);
            userReports.setTableName(tableName);
            this.userReportsService.updateById(userReports);
        }

        String url = zfserviceUrl + "/formula/calc_report";
        Map<String, String> paramsMap = new HashMap<>();
        paramsMap.put("report_id", reportId);
        paramsMap.put("calc_date", calcDate.toString());
        JSONObject object = HttpClientUtil.sendGet(url, paramsMap);
        if (object.get("code") != null && Integer.parseInt(object.get("code").toString()) == 0) {
            Map maps = (Map) object.get("data");
            this.buildTableDate(userReports, maps, userReportsFieldList, calcDate.toString());
            this.exportXls(reportId, userReports.getReportName(),
                    Date.from(calcDate.atStartOfDay(ZoneId.systemDefault()).toInstant()),
                    maps, null, userReportsFieldList);
            log.info("生成成功 calcDate:{}", calcDate);
        } else {
            if (object.containsKey("message") && object.get("message") != null) {
                //	return Result.error(object.get("message").toString());
                throw new Error(object.get("message").toString());
            } else {
                //return Result.error("生成失败");
                throw new Error("生成失败");
            }
        }
    }

    public void exportXls(String reportId, String reportName, Date calcDate, Map maps, List<Map<String, Object>> result, List<UserReportsField> userReportsFieldList) {

        List<Map<String, Object>> colList = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> valList = new ArrayList<Map<String, Object>>();
        if (result != null && result.size() > 0) {//已存在对应表数据
            for (int j = 1; j < userReportsFieldList.size() + 1; j++) {
                Map<String, Object> mapHead = new HashMap<>();
                mapHead.put("column", userReportsFieldList.get(j - 1).getFieldName());
                mapHead.put("value", "t." + userReportsFieldList.get(j - 1).getTableColumn());
                colList.add(mapHead);
            }
            valList = result;
        } else {
            List<BuildReport> pageList = new ArrayList<BuildReport>();
            try {

                for (Object map : maps.entrySet()) {
                    JSONObject detail = (JSONObject) ((Map.Entry) map).getValue();
                    for (Object mapDetail : detail.entrySet()) {
                        BuildReport vo = new BuildReport();
                        vo.setField(((Map.Entry) map).getKey().toString());
                        vo.setSlotName(((Map.Entry) mapDetail).getKey().toString());
                        vo.setFieldValue(((Map.Entry) mapDetail).getValue().toString());
                        pageList.add(vo);
                    }
                }

                int index = 1;
                for (Object map : maps.entrySet()) {
                    Map<String, Object> mapHead = new HashMap<String, Object>();
                    mapHead.put("column", ((Map.Entry) map).getKey());
                    mapHead.put("value", "t.vl_" + index);
                    colList.add(mapHead);
                    index++;
                }

                List<String> slotList = pageList.stream().map(BuildReport::getSlotName).distinct().collect(Collectors.toList());
                for (int i = slotList.size(); i-- > 0; ) {
                    Map<String, Object> map = getSlotMap(pageList, colList, slotList.get(i));
                    valList.add(map);
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error(e.getMessage(), e);
                //return Result.error("生成失败");
            }
        }

        TemplateExportParams params = new TemplateExportParams(reportTmpPath);
        Map<String, Object> value = new HashMap<String, Object>();
        value.put("title", reportName);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        value.put("date", simpleDateFormat.format(new Date()));

        value.put("colList", colList);
        value.put("valList", valList);
        params.setColForEach(true);
        Workbook workbook = ExcelExportUtil.exportExcel(params, value);
        if (workbook != null) ;
        try {
            Date d = new Date();
            String fileName = reportName + DateUtils.yyyymmddhhmmss.get().format(d);
            String ctxPath = exportPath;
            File file = new File(ctxPath);
            if (!file.exists()) {
                // 创建文件根目录
                file.mkdirs();
            }
            FileOutputStream fileOutputStream = new FileOutputStream(file.getPath() + "/" + fileName + ".xls");
            //写入输出流
            workbook.write(fileOutputStream);
            ReportCronJobData reportCronJobData = new ReportCronJobData();
            reportCronJobData.setParamId("0");
            reportCronJobData.setReportId(Integer.parseInt(reportId));
            reportCronJobData.setReportName(reportName);
            reportCronJobData.setFileUrl(fileName + ".xls");
            reportCronJobData.setCalcDate(calcDate);
            reportCronJobData.setCreateTime(new Date());
            reportCronJobDataService.save(reportCronJobData);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关流
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
//
//        try {
//            response.setCharacterEncoding("UTF-8");
//            response.setHeader("content-Type", "application/vnd.ms-excel");
//            response.setHeader("Content-Disposition",
//                    "attachment;filename=" + URLEncoder.encode(userReports.getReportName(), "UTF-8"));
//            workbook.write(response.getOutputStream());
//        } catch (IOException e) {
//            try {
//                throw new Exception(e.getMessage());
//            } catch (Exception e1) {
//                e1.printStackTrace();
//            }
//        }
    }


    @NotNull
    private Map<String, Object> getSlotMap(List<BuildReport> pageList, List<Map<String, Object>> colList, String slot) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("slot", slot);
        for (int i = 0; i < colList.size(); i++) {
            Map<String, Object> col = colList.get(i);
            String field = col.get("column").toString();
            String fieldValue = pageList.stream().filter(o -> o.getSlotName().equals(slot) && o.getField().equals(field)).findAny().get().getFieldValue();
            String num = col.get("value").toString().replace("t.", "");
            map.put(num, fieldValue);
        }

        //map.put("vl_2", 4);
        return map;
    }

    //生成表单数据
    public void buildTableDate(UserReports userReports, Map maps, List<UserReportsField> userReportsFieldList, String calcDate) {
        List<Map<String, Object>> colList = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> valList = new ArrayList<Map<String, Object>>();

        List<BuildReport> pageList = new ArrayList<>();
        for (Object map : maps.entrySet()) {
            JSONObject detail = (JSONObject) ((Map.Entry) map).getValue();
            for (Object mapDetail : detail.entrySet()) {
                BuildReport vo = new BuildReport();
                vo.setField(((Map.Entry) map).getKey().toString());
                vo.setSlotName(((Map.Entry) mapDetail).getKey().toString());
                vo.setFieldValue(((Map.Entry) mapDetail).getValue().toString());
                pageList.add(vo);
            }
        }

        for (int j = 1; j < userReportsFieldList.size() + 1; j++) {
            Map<String, Object> mapHead = new HashMap<String, Object>();
            mapHead.put("column", userReportsFieldList.get(j - 1).getFieldName());
            mapHead.put("value", "t.vl_" + j);
            colList.add(mapHead);
        }

        List<String> slotList = pageList.stream().map(BuildReport::getSlotName).distinct().sorted().collect(Collectors.toList());
        for (int i = 0; i < slotList.size(); i++) {
            Map<String, Object> map = getSlotMap(pageList, colList, slotList.get(i));
            map.put("calc_date", calcDate);
            // map.put("id", UUID.randomUUID().toString().replaceAll("-", ""));
            valList.add(map);
            this.userReportsService.addTableRow(userReports.getTableName(), map);
        }
    }
}
